
/*
 * =====================================================================================
 *
 *       Filename:  Complex.cpp
 *
 *    Description:  Implementation of the Complex class
 *
 *        Version:  1.0
 *        Created:  11/24/11 21:03:12
 *       Revision:  none
 *       Compiler:  g++
 *
 *         Author:  LittleQ Su (), 98703060@nccu.edu.tw
 *        Company:  National Chengchi University, The Department of Computer Science
 *
 * =====================================================================================
 */
/*The output of a complex number should be like this:
 *
 *   1+2i
 *   1-2i
 *   -3+2i
 *   -3-2i
 *   3
 *   0
 *   -2
 *   2i
 *   -2i
 *
 * */
#include "headers.h"
#include "Complex.h"

using namespace std;

// Constructorso
Complex::Complex() {
    this -> real = double(0);
    this -> fake = double(0);
}

Complex::Complex(const Complex &other) {
    this -> real = other.getReal();
    this -> fake = other.getImag();
}

Complex::Complex(double other) {
    this -> real = other;
    this -> fake = 0;
}

Complex::Complex(double real, double fake) {
    this -> real = real;
    this -> fake = fake;
}

// Public methods
void Complex::set(double real, double fake) {
    this -> real = real;
    this -> fake = fake;
}

double Complex::getReal() const {
    return this -> real;
}

double Complex::getImag() const {
    return this -> fake;
}

string Complex::toString() const {
    stringstream oss;

    if (this -> real == 0 && this -> fake == 0 ) {
        return "0";
    }

    if (this -> real != 0) {
        oss << this->getReal();
        oss << this->_getImagPositiveSign();
    }
    if (this -> fake != 0) {
        oss << this->getImag();
        oss << "j";
    }

    return oss.str();
    
}

float Complex::absolute() const {
    return sqrt(pow(this->real,2) + pow(this->fake,2));
}

Complex Complex::conjugate() const {
    Complex result(this->real, this->fake * -1 );
    return result;
}


// Operator overloading
const Complex Complex::operator+(const Complex &other) const {
    double real_total, fake_total;
    real_total = this -> real + other.getReal();
    fake_total = this -> fake + other.getImag();
    Complex result(real_total, fake_total);
    return result;
}

const Complex Complex::operator-(const Complex &other) const {
    double real_total, fake_total;
    real_total = this -> real - other.getReal();
    fake_total = this -> fake - other.getImag();
    Complex result(real_total, fake_total);
    return result;
}

const Complex Complex::operator*(const Complex &other) const {
    double real_total, fake_total;
    Complex a, b;
    a = *this;
    b = other;
    real_total = a.getReal()*b.getReal() - a.getImag()*b.getImag();
    fake_total = a.getReal()*b.getImag() + a.getImag()*b.getReal();
    Complex result(real_total, fake_total);
    return result;
}

const Complex Complex::operator*(const double other) const {
    Complex b(other, 0);
    return (*this) * b;
}


const Complex Complex::operator/(const Complex &other) const {
    Complex up_part, down_part, c;
    up_part = *this;
    down_part = other;
    c = down_part.conjugate();
    up_part*=c;
    down_part*=c;

    Complex result(up_part.getReal() / down_part.getReal() , up_part.getImag() / down_part.getReal());
    return result;
}

const Complex Complex::operator/(const double other) const {
    Complex b(other, 0);
    return (*this) / b;
}

Complex& Complex::operator++() {
    this->real+=1;
    return *this;
}

Complex& Complex::operator--() {
    this->real-=1;
    return *this;
}

Complex& Complex::operator++(int idx) {
    this->real+=1;
    return *this;
}

Complex& Complex::operator--(int idx) {
    this->real-=1;
    return *this;
}

Complex& Complex::operator+=(const Complex &rhs) {
    this->set(this->real + rhs.getReal(), this->fake + rhs.getImag());
    return *this;
}

Complex& Complex::operator-=(const Complex &rhs) {
    this->set(this->real - rhs.getReal(), this->fake - rhs.getImag());
    return *this;
}

Complex& Complex::operator*=(const Complex &rhs) {
    Complex result = (*this) * rhs;
    this -> set(result.getReal(), result.getImag());
    return *this;
}

Complex& Complex::operator/=(const Complex &rhs) {
    Complex result = (*this) / rhs;
    this -> set(result.getReal(), result.getImag());
    return *this;
}

Complex& Complex::operator=(const Complex &rhs) {
    if (this == &rhs) {
        return *this;
    }
    this->set(rhs.getReal(), rhs.getImag());
    return *this;
}

bool Complex::operator==(const Complex &other) const {
    return (this -> real == other.getReal()) && (this -> fake == other.getImag());
}
bool Complex::operator==(const double r) const {
    return this->absolute() == r;
}

bool Complex::operator!=(const Complex &other) const {
    return !(*this == other);
}
bool Complex::operator!=(const double r) const {
    Complex other(r,0);
    return *this != other;
}

bool Complex::operator>=(const Complex &other) const {
    return other>(*this) || (other == *this);
}
bool Complex::operator>=(const double r) const {
    Complex other(r, 0);
    return *this >= other;
}

bool Complex::operator>(const Complex &other) const {
    return (this->getReal()>other.getReal()) || (this->getImag()>other.getImag());
}
bool Complex::operator>(const double r) const {
    Complex other(r,0);
    return *this > other;
}

bool Complex::operator<=(const Complex &other) const {
    return other<(*this) || (other == *this);
}
bool Complex::operator<=(const double r) const {
    Complex other(r,0);
    return *this <= other;
}

bool Complex::operator<(const Complex &other) const {
    return (this->getReal()<other.getReal()) || (this->getImag()<other.getImag());
}
bool Complex::operator<(const double r) const {
    Complex other(r,0);
    return *this < other;
}

// Private methods
string Complex::_getImagPositiveSign() const {
    if (this -> fake > 0) {
        return "+";
    } else {
        return "";
    }
}



// friends
ostream &operator<< (ostream &out, const Complex L) {
    out << L.toString();
    return out;
}

istream &operator>> (istream &in, Complex &L) {
    double real, fake;
    in >> real >> fake;
    L.set(real, fake);
    return in;
}

Complex operator-( const Complex &other ) {
    return other * -1;
}
